package cn.moefly.common.component.support;

import lombok.AllArgsConstructor;

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

@AllArgsConstructor
public abstract class DelayTask<T> implements Delayed {

    T data;

    Consumer<T> expireConsumer;


    /**
     * 过期时，使用 expireConsumer对数据进行处理
     */
    public void doExpireAction(){
        expireConsumer.accept(data);
    }


    @Override
    public int compareTo(Delayed o) {
        return Long.compare(this.getDelay(TimeUnit.MICROSECONDS),o.getDelay(TimeUnit.MICROSECONDS));
    }

    @Override
    public long getDelay(TimeUnit unit) {
        var myExpTime = timeVal();
        var myUnit = timeUnit();
        var delayDuration = myUnit.toMillis(myExpTime) - System.currentTimeMillis();
        return unit.convert(delayDuration,TimeUnit.MILLISECONDS);
    }

    /**
     * 当前任务的过期时间的数值，从data或者各种奇怪的地方获取，
     * 时间的单元必须与{@link #timeUnit()}返回的Unit对应
     */
    protected abstract long timeVal();


    /**
     * 当前任务的过期时间的单元，必须与{@link #timeVal()}中代表单元的一致
     */
    protected abstract TimeUnit timeUnit();


    /**
     * 通常需要做进一步的深层重复检查是否过期
     *
     * 并且因为在外部修改队列元素的过期值会带来队列重排序的问题，
     * 我们可以通过过期检查和下面的更新时间{@link #updateExpireTime}方法，
     * 来重新根据data中的数据重新构建过期时间，然后再重新入队列
     *
     * TODO：搞清楚DelayQueue是怎么重排序的
     */
    public abstract boolean ifTrulyExpires();

    public abstract void updateExpireTime();


}
